/*
 * XMLTree.cpp
 *
 *  Created on: Jul 14, 2013
 *      Author: Dan
 */

#include "XMLTree.h"

namespace monkeyXML {

XMLTree::XMLTree() {
	theChildren = NULL;
	isClosingTag = true;
	theNode = NULL;
	isText = true;
}

XMLTree::XMLTree(std::istream& anInputStream) {
	//Read off whitespace
	//If the tree is representing a tag, read the tag
	//if the tag isn't the closing tag of a pair, make the tag
	// (the parsing of attributes is done by the tag itself)
	//if the tag has a text entry afterwards, create a child for that text
	//if this isn't a closing tag and not empty, read in its children tags.
	theChildren = NULL;	// A tree consists of a node(its data) and its child trees
	theNode = NULL; 	   //   if there are no child trees, theChildren = NULL.
	isClosingTag = false;  //tells if this tree is a leaf.
	bool inQuotes = false; //for parsing strings that contain special chars
	isText = false;        //tells if this tree represents a text node.

	std::string value;     //the string that represents the text of a XMLNode

	char current = 0;      //a char read from the input to build 'value'

	anInputStream.get(current);

	//read off whitespace
	while (current == '\n' || current == ' ' || current == '\r') {
		anInputStream.get(current);
	}
	if (current == '<') {
		while (current != '>' || inQuotes == true) {
			value += current;
			anInputStream.get(current);
			if (current == '"') {
				inQuotes = !inQuotes;
			}
			if (current == '/' && inQuotes == false) {
				isClosingTag = true;
			}
		}
		value += current;
		theNode = new XMLTag(value);
		//std::cout << theNode->toString()<<std::endl;
		if (!isClosingTag) {
			XMLTree* child = new XMLTree(anInputStream);
			theChildren = new std::list<XMLTree*>;
			if (child->isText == true) {
				theChildren->push_front(child);
			}

			//std::cout << child << " " << theChildren << "\n";
			while (!(child->isClosingTag) && anInputStream) {
				theChildren->push_back(child);
				child = new XMLTree(anInputStream);
				//std::cout <<"Try adding new child "<<child->getTag()<<" "<<child<<std::endl;

			}
		}

	} else {
		isText = true;
		isClosingTag = true;
		while (anInputStream && (current != '<' || inQuotes == true)) {
			value += current;
			anInputStream.get(current);
			if (current == '"') {
				inQuotes = !inQuotes;
			}
		}
		while (current != '>' && anInputStream) {
			anInputStream.get(current);
		}

		theNode = new XMLText(value);
		//std::cout << value << " " << isClosingTag << std::endl;
	}
	if (theChildren != NULL) {
		theChildIterator = theChildren->end();
	}
}

XMLTree::XMLTree(const std::string& aTag,
		const std::vector<std::string>& anAttLabels,
		const std::vector<std::string>& anAttVals,
		std::list<XMLTree*>* aChildArray) throw (std::length_error) {
	isText = false;
	isClosingTag = false;
	theChildren = new std::list<XMLTree*>;
	for (std::list<XMLTree*>::iterator it = aChildArray->begin();
			it != aChildArray->end(); ++it) {
		XMLTree* tmp = new XMLTree(**it);
		theChildren->push_back(tmp);
	}
	try {
		theNode = new XMLTag(aTag, anAttLabels, anAttVals);
	} catch (std::length_error& e) {
		throw e;
	}
}

XMLTree::XMLTree(const std::string& aText) {
	isText = true;
	isClosingTag = true;
	theChildren = NULL;
	theNode = new XMLText(aText);
}

XMLNode* XMLTree::getNode() {
	//std::cout<<theNode<<"\n";
	return theNode;
}

XMLTree* XMLTree::getNextChild() {
	theChildIterator++;
	if (theChildIterator == theChildren->end()) {
		theChildIterator = theChildren->begin();
	}
	return *theChildIterator;
}

int XMLTree::childCount() {
	int results = 0;
	if (theChildren != NULL) {
		results = theChildren->size();
	}
	return results;
}

std::string XMLTree::getTag() {
	return theNode->getTag();
}

XMLTree::XMLTree(const XMLTree& another) {
	theChildren = new std::list<XMLTree*>;
	for (std::list<XMLTree*>::iterator it = another.theChildren->begin();
			it != another.theChildren->end(); ++it) {
		XMLTree* tmp = new XMLTree(**it);
		theChildren->push_back(tmp);
	}
	theChildIterator = another.theChildIterator;
	isText = another.isText;
	if (isText) {
		theNode = new XMLText(another.theNode->getTag());
	} else {

		theNode = new XMLTag(*((XMLTag*) another.theNode));
	}
	isClosingTag = another.isClosingTag;
}

void XMLTree::writeToStream(std::ostream& aStream) throw (std::exception) {
	if (!isText) {
		aStream << '<';
	}
	aStream << (theNode->toString());

	if (theChildren != NULL) {
		aStream << '>';
		aStream << '\n'; //used only to debug

		for (std::list<XMLTree*>::iterator it = theChildren->begin();
				it != theChildren->end(); ++it) {
			(*it)->writeToStream(aStream);
		}
		aStream << '<';
		aStream << '/';
		aStream << theNode->getTag();
	} else if (!isText) {
		aStream << '/';
	}
	if (!isText) {
		aStream << '>';
		aStream << '\n'; //used only to debug
	}
}

XMLTree::~XMLTree() {
	Log::debug("Safely destroyed " + theNode->getTag());
	while (theChildren != NULL && theChildren->empty() == false) {
		delete theChildren->front();
		//std::cout<<theChildren->front()<<"\n";
		theChildren->pop_front();
	}
	if (theChildren != NULL) {
		delete theChildren;
	}
	if (theNode != NULL) {
		delete theNode;
	}
}

} /* namespace monkeyXML */
